package com.lyj.thread.syncutil;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * CyclicBarrier:CyclicBarrier（循环屏障），它是一个同步助手工具，它允许多个线程在执行完相应的操作之后彼此等待共同到达一个障点（barrier point）。
 * CyclicBarrier 也非常适合用于某个串行化任务被分拆成若干个并行执行的子任务，当所有的子任务都执行结束之后再继续接下来的工作。
 * 构造方法：
 * CyclicBarrier(int parties)：参数 parties  表示屏障拦截的线程数量，必须有 parties 个线程调用了 await() 方法后此屏障才会被打开。各个线程才能继续执行任务
 * CyclicBarrier(int parties, Runnable barrierAction)：参数 parties  同上。参数 barrierAction 表示当所有线程都到达屏障点后，需要执行的任务。只有执行玩指定的任务，各个子线程才能继续执行自己的任务
 * 注意：
 * 1，parties 参数必须 大于 0。否则会抛出异常。
 * 2，barrierAction 可以为null,  因为 barrierAction  中的代码是在最后一个到达屏障点的线程中执行，建议不要在此内部实现耗时较大的任务业务逻辑。
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new EatTask());
        for (int i = 0; i < 3; i++) {
            new Thread(new WashTask(cyclicBarrier)).start();
        }

    }

}

/**
 * 子线程
 */
class WashTask implements Runnable {
    CyclicBarrier cyclicBarrier;

    public WashTask(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;

    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + "，到达屏障");
//            TimeUnit.MILLISECONDS.sleep(1000);
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName() + "，结束");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (BrokenBarrierException e) {
            throw new RuntimeException(e);
        }

    }
}

/**
 * 所有子线程到达屏障后执行的任务,独占锁
 */
class EatTask implements Runnable {
    @Override
    public void run() {
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + "，所有子线程到达屏障，开始执行任务");
    }
}

class CyclicBarrierExample {
    // 游客
    static class Tourist extends Thread {
        private final int touristId;
        private final CyclicBarrier barrier;

        public Tourist(int touristId, CyclicBarrier barrier) {
            this.touristId = touristId;
            this.barrier = barrier;
        }

        @Override
        public void run() {
            try {
                System.out.printf("游客: %d 正在奔赴客车路上. \n", touristId);
                TimeUnit.MILLISECONDS.sleep(1000); //模拟游客等待
//                System.out.printf("游客: %d 已上车, 等待其他游客 \n", touristId);
                barrier.await(); // 加入屏障等待其他游客
                System.out.printf("游客: %d =====. \n", touristId);
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

    }


    public static void main(String[] args) {

        CyclicBarrier barrier = new CyclicBarrier(11);

        for (int i = 0; i < 10; i++) {
            new Tourist(i, barrier).start();
        }
        try {
            barrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }


        System.out.println(Thread.currentThread().getName()+"，所有的游客都已上车, 开始发车去往景点");

    }
}

